# -*- coding: utf-8 -*-

from error import LTSError

class Alphabet:
	"""
		Esta clase representa el alfabeto de un LTS.
		
		Un alfabeto es un conjunto de eventos. Los eventos estan representados 
		por cadenas de caracteres (strings), y se dividen en cuatro tipos: 
		observables, no observables, de falla y de sincronizacion. Para 
		diferenciar a que tipo pertence cada evento, se exige que estos 
		comienzen con un caracter en particular; los eventos observables 
		deben comenzar con el caracter 'o', lo no observables con el caracter 
		'u', los de falla con 'f', y los de sincronizacion con 'c'.
	
		Para los metodos de esta clase, los posibles valores del argumento
		'event_type' son:
			'o'	=>	Conjutno de eventos observables.
			'u'	=>	Conjunto de eventos no observables.
			'f'	=>	Conjunto de eventos de falla.
			'c'	=>	Conjunto de eventos de sincronizacion.
		En caso de proporcionar un valor incorrecto se produce una excepcion
		de tipo LTSError.
	"""
	
	def __init__ (self):
		self.sets = dict()
		# Conjunto de eventos observables.
		self.sets['o'] = set()
		# Conjunto de eventos no observables.
		self.sets['u'] = set()
		# Conjunto de eventos de falla.
		self.sets['f'] = set()
		# Conjunto de eventos de sincronizacion.
		self.sets['c'] = set()
	
	def __copy__ (self):
		result = Alphabet()
		result.sets['o'] = set(self.sets['o'])
		result.sets['u'] = set(self.sets['u'])
		result.sets['f'] = set(self.sets['f'])
		result.sets['c'] = set(self.sets['c'])
		return result
	
	def is_event (self, event, event_type):
		"""
			Descripcion:
				Dice si el evento 'event' existe en el conjunto de eventos 
				indicado por 'event_type'.
			Arguemtnos:
				event		-	Una cadena de caracteres que repcenta un evento.
				event_type	-	Un caracter que especifica a que tipo de evento 
								pertenece. Sus posibles valores son: o|u|f|c.
			Retorno:
				True	-	Si el evento pertence al alfabeto.
				Falso	-	Si no.
		"""
		try:
			return event in self.sets[event_type]
		except KeyError:
			raise LTSError("Incorrect type event:", event_type)
	
	def add_event (self, event, event_type):
		"""
			Descripcion:
				Agrega el evento 'event' al conjunto de eventos indicado por
				'event_type'.
			Arguemtnos:
				event		-	Una cadena de caracteres que repcenta un evento.
				event_type	-	Un caracter que especifica a que tipo de evento 
								pertenece. Sus posibles valores son: o|u|f|c.
			Retorno:
				No tiene.
		"""
		try:
			(self.sets[event_type]).add(event)
		except KeyError:
			raise LTSError("Incorrect type event:", event_type)
	
	def remove_event (self, event, event_type):
		"""
			Descripcion:
				Elimina el evento 'event' del conjunto de eventos indicado por
				'event_type'.
			Arguemtnos:
				event		-	Una cadena de caracteres que repcenta un evento.
				event_type	-	Un caracter que especifica a que tipo de evento 
								pertenece. Sus posibles valores son: o|u|f|c.
			Retorno:
				No tiene.
		"""
		try:
			(self.sets[event_type]).remove(event)
		except KeyError:
			raise LTSError("Incorrect type event", event_type)
	
	def get_event_set (self, event_type):
		"""
			Descripcion:
				Devuelve el conjunto de eventos indicado por 'event_type'.
				NOTA: Se devuelve una referencia al conjunto, no una copia.
				IMPORTANTE: Se recomienda no hacer modificaciones al conjunto 
				a traves de esta referencia.
			Arguemtnos:
				event_type	-	Un caracter que especifica el tipo de evento.
								Sus posibles valores son: o|u|f|c.
			Retorno:
				Devuelve una instancia de la clase Set() la cual tiene el 
				conjunto de eventos de tipo "event_type" del alfabeto.
		"""
		try:
			return self.sets[event_type]
		except KeyError:
			raise LTSError("Incorrect type event", event_type)
	
	def union (self, alphabet):
		"""
			Descripcion:
				Une dos alfabaetos.
				Crea y devuelve un nuevo alfabeto el cual es el resultado de la
				union de los alfabetos 'self' y 'alphabet'.
			Arguemtnos:
				alphabet	-	Una instancia de la clase Alphabet().
			Retorno:
				Devuelve una nueva instancia de la clase Alphabet() la cual 
				contiene la union de los eventos de los dos alfabetos.
		"""
		result = Alphabet()
		result.sets['o'] = self.sets['o'].union(alphabet.sets['o'])
		result.sets['u'] = self.sets['u'].union(alphabet.sets['u'])
		result.sets['f'] = self.sets['f'].union(alphabet.sets['f'])
		result.sets['c'] = self.sets['c'].union(alphabet.sets['c'])
		return result
